package com.fessc.develop.handler;

import com.fessc.develop.base.RSATools;
import com.fessc.develop.base.RsaTool;
import com.fessc.develop.entity.KeyPropertiesVo;
import com.fessc.develop.utils.BusiUtil;
import com.fessc.develop.utils.ExceptionUtil;
import com.mongodb.client.gridfs.model.GridFSFile;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsOperations;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;

import javax.annotation.Resource;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

@Slf4j
@Service
public class SignHandler {

    @Resource
    private KeyPropertiesVo keyPropertiesVo;

    @Resource
    private GridFsTemplate gridFsTemplate;

    @Resource
    private GridFsOperations gridFsOperations;

    /**
     * post 报文解密
     *
     * @param toBeDecrypt 解密报文
     * @return string
     */
    public String decrypt(String toBeDecrypt) {
        RsaTool rsaTool = new RsaTool(this.getOrgPubKey(keyPropertiesVo.getPublicKey()), this.getPriKey());
        //String pricer= "D:\\Code\\project\\develop\\private.key";
        //String pubcer= "D:\\Code\\project\\develop\\public.cer";
        //RSATools rsaTool= new RSATools(pricer,pubcer);
        return rsaTool.decrypt(toBeDecrypt);
    }

    /**
     * post 报文加密
     *
     * @param toBeEncrypt 加密报文
     * @param pubCertId   平台公钥
     * @return string
     */
    public String encrypt(String toBeEncrypt, String pubCertId) {
        RsaTool rsaTool = new RsaTool(this.getOrgPubKey(pubCertId), this.getPriKey());
        //String pricer= "D:\\Code\\project\\develop\\private.key";
        //String pubcer= "D:\\Code\\project\\develop\\public.cer";
        //RSATools rsaTool= new RSATools(pricer,pubcer);
        return rsaTool.encrypt(toBeEncrypt);
    }

    /**
     * post 获取银行私钥
     *
     * @return PrivateKey
     */
    private PrivateKey getPriKey() {
        GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(keyPropertiesVo.getPrivateKey())));
        log.info("私钥名称ID：" + gridFSFile.getFilename() + "-" + keyPropertiesVo.getPrivateKey());
        if (BusiUtil.isNull(gridFSFile)) {
            log.error("根据文件Id查询MongoDB获取私钥失败！");
            throw ExceptionUtil.businessException("EE4004");
        }
        InputStream inputStream = null;
        try {
            GridFsResource resource = gridFsOperations.getResource(gridFSFile);
            inputStream = resource.getInputStream();
            byte[] encodedPriKey = StreamUtils.copyToByteArray(inputStream);
            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(encodedPriKey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(priKeySpec);
        } catch (Exception e) {
            throw ExceptionUtil.businessException("EE4006");
        } finally {
            try {
                if (inputStream !=null ) {
                    inputStream.close();
                }
            } catch (Exception e) {
                log.info("关闭文件输入流异常： " + e.getMessage());
            }
        }
    }

    /**
     * post 获取平台公钥
     *
     * @return PrivateKey
     */
    private PublicKey getOrgPubKey(String pubCertId) {

        InputStream inputStream = null;
        GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(pubCertId)));
        log.info("公钥名称ID：" + gridFSFile.getFilename() + "-" + pubCertId);
        if (BusiUtil.isNull(gridFSFile)) {
            log.error("根据文件Id查询MongoDB，获取公钥失败！");
            throw ExceptionUtil.businessException("EE4004");
        }
        try {
            GridFsResource resource = gridFsOperations.getResource(gridFSFile);
            inputStream = resource.getInputStream();
            byte[] encodedPubKey = StreamUtils.copyToByteArray(inputStream);
            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encodedPubKey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePublic(pubKeySpec);
        } catch (Exception e) {
            log.error("生成公钥失败！", e);
            throw ExceptionUtil.businessException("EE4005");
        } finally {
            try {
                if (inputStream !=null ) {
                    inputStream.close();
                }
            } catch (Exception e) {
                log.info("关闭文件输出流异常： " + e.getMessage());
            }
        }
    }
}
